package com.leyou.order.service;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.leyou.auth.entity.UserInfo;
import com.leyou.client.PayClient;
import com.leyou.common.pojo.PageResult;
import com.leyou.common.utils.IdWorker;
import com.leyou.order.interceptor.LoginInterceptor;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.mapper.OrderStatusMapper;
import com.leyou.order.pojo.Order;
import com.leyou.order.pojo.OrderDetail;
import com.leyou.order.pojo.OrderStatus;
import com.leyou.pay.entity.AliPayParam;
import com.leyou.pay.entity.PayState;
import com.leyou.pay.entity.WxPayParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderService {

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper detailMapper;

    @Autowired
    private OrderStatusMapper statusMapper;

    @Autowired
    private PayClient payClient;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private AmqpTemplate amqpTemplate;

    private static final String EXCHANGE = "leyou.stock.exchange";

    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);

    @Transactional
    public Long createOrder(Order order) {
        // 生成orderId
        long orderId = idWorker.nextId();
        // 获取登录用户
        UserInfo user = LoginInterceptor.getLoginUser();
        // 初始化数据
        order.setBuyerNick(user.getUsername());
        order.setBuyerRate(false);
        order.setCreateTime(new Date());
        order.setOrderId(orderId);
        order.setUserId(user.getId());
        // 保存数据
        this.orderMapper.insertSelective(order);

        // 保存订单状态
        OrderStatus orderStatus = new OrderStatus();
        orderStatus.setOrderId(orderId);
        orderStatus.setCreateTime(order.getCreateTime());
        orderStatus.setStatus(1);// 初始状态为未付款

        this.statusMapper.insertSelective(orderStatus);

        // 订单详情中添加orderId
        order.getOrderDetails().forEach(od -> od.setOrderId(orderId));
        // 保存订单详情,使用批量插入功能
        this.detailMapper.insertList(order.getOrderDetails());

        logger.debug("生成订单，订单编号：{}，用户id：{}", orderId, user.getId());

        return orderId;
    }

    public Order queryById(Long id) {
        // 查询订单
        Order order = this.orderMapper.selectByPrimaryKey(id);

        // 查询订单详情
        OrderDetail detail = new OrderDetail();
        detail.setOrderId(id);
        List<OrderDetail> details = this.detailMapper.select(detail);
        order.setOrderDetails(details);

        // 查询订单状态
        OrderStatus status = this.statusMapper.selectByPrimaryKey(order.getOrderId());
        order.setStatus(status.getStatus());
        return order;
    }

    public PageResult<Order> queryUserOrderList(Integer page, Integer rows, Integer status) {
        try {
            // 分页
            PageHelper.startPage(page, rows);
            // 获取登录用户
            UserInfo user = LoginInterceptor.getLoginUser();
            // 创建查询条件
            Page<Order> pageInfo = (Page<Order>) this.orderMapper.queryOrderList(user.getId(), status);

            return new PageResult<>(pageInfo, pageInfo.getTotal());
        } catch (Exception e) {
            logger.error("查询订单出错", e);
            return null;
        }
    }

    @Transactional
    public Boolean updateStatus(Long id, Integer status) {
        OrderStatus record = new OrderStatus();
        record.setOrderId(id);
        record.setStatus(status);
        // 根据状态判断要修改的时间
        switch (status) {
            case 2:
                record.setPaymentTime(new Date());// 付款
                break;
            case 3:
                record.setConsignTime(new Date());// 发货
                break;
            case 4:
                record.setEndTime(new Date());// 确认收获，订单结束
                break;
            case 5:
                record.setCloseTime(new Date());// 交易失败，订单关闭
                break;
            case 6:
                record.setCommentTime(new Date());// 评价时间
                break;
            default:
                return null;
        }
        int count = this.statusMapper.updateByPrimaryKeySelective(record);
        return count == 1;
    }

    private Map<String, String> getSkuInfo(Long id){
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderId(id);
        List<OrderDetail> orderDetails = this.detailMapper.select(orderDetail);

        if(!CollectionUtils.isEmpty(orderDetails)){
            int count = orderDetails.size();
            StringBuffer bufferTitle = new StringBuffer();
            StringBuffer bufferId = new StringBuffer();
            orderDetails.forEach(o ->{
                if(count > 1){
                    bufferId.append(o.getSkuId().toString() + "-");
                    bufferTitle.append(o.getTitle() + "/");
                }else {
                    bufferId.append(o.getSkuId().toString());
                    bufferTitle.append(o.getTitle());
                }
            });
            Map<String, String> map = new HashMap<>();
            map.put("ids", bufferId.toString());
            map.put("body", bufferTitle.toString());
            return map;
        }
        return null;
    }

    public String goAliPay(Long id) {
        try {
            // 查询订单
            Order order = this.orderMapper.selectByPrimaryKey(id);

            //商户订单号，商户网站订单系统中唯一订单号，必填
            String out_trade_no = id.toString();
            //付款金额，必填
            String total_amount = BigDecimal.valueOf(Long.valueOf(order.getActualPay())).divide(new BigDecimal(100)).toString();
            //订单名称，必填
            String subject = "乐优旗舰店";
            //商品描述，可空
            String body = this.getSkuInfo(id).get("body");
            // 该笔订单允许的最晚付款时间，逾期将关闭交易。
            // 取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。
            // 该参数数值不接受小数点， 如 1.5h，可转换为 90m。
            String timeout_express = "10m";

            AliPayParam payParam = new AliPayParam();
            payParam.setOutTradeNo(out_trade_no);
            payParam.setTotalAmount(total_amount);
            payParam.setSubject(subject);
            payParam.setBody(body);
            payParam.setTimeoutExpress(timeout_express);
            payParam.setProductCode("FAST_INSTANT_TRADE_PAY");

            return this.payClient.aliPay(payParam);

        } catch (Exception e) {
            logger.error("初始化支付页面失败!");
            e.printStackTrace();
        }
        return null;
    }

    public String createPayUrl(Long orderId) {
        // 先查询redis是否存在url
        String key = "ly.pay.url." + orderId;
        try {
            String url = this.redisTemplate.opsForValue().get(key);
            if (StringUtils.isNotBlank(url)) {
                return url;
            }
        } catch (Exception e) {
            logger.error("查询缓存付款链接异常,订单编号：{}", orderId, e);
        }

        // 没有则重新发送微信支付，获取url
        try {
            // 查询订单
            Order order = this.orderMapper.selectByPrimaryKey(orderId);

            WxPayParam wxPayParam = new WxPayParam();
            wxPayParam.setBody("乐优商城旗舰店");
            // 商品描述
            wxPayParam.setDetail(this.getSkuInfo(orderId).get("body"));
            // 订单号
            wxPayParam.setOutTradeNo(orderId.toString());
            // 货币
            wxPayParam.setFeeType("CNY");
            // 金额，单位是分
            wxPayParam.setTotalFee(order.getActualPay().toString());
            // 调用微信支付的终端IP（乐优商城的IP）
            wxPayParam.setSpbillCreateIp("127.0.0.1");
            // 回调地址，付款成功后的接口
            wxPayParam.setNotifyUrl("http://test.leyou.com/wxpay/notify"); // 暂时没有实现这个回调地址
            // 交易类型为扫码支付
            wxPayParam.setTradeType("NATIVE");
            // 商品id
            wxPayParam.setProductId(this.getSkuInfo(orderId).get("ids"));

            // 发起微信支付，获取url
            String url = this.payClient.wxPay(wxPayParam);
            if(StringUtils.isNotEmpty(url)){
                // 将付款地址缓存，时间为10分钟
                this.redisTemplate.opsForValue().set(key, url, 10, TimeUnit.MINUTES);
                return url;
            }
            return null;
        } catch (Exception e) {
            logger.error("创建预交易订单异常", e);
            return null;
        }
    }

    @Transactional
    public PayState queryOrder(Long orderId) {
        try {
            PayState payState = this.payClient.queryPayStatus(orderId);
            if(StringUtils.equals(payState.toString(), "SUCCESS")){
                // 修改订单状态
                this.updateStatus(orderId, 2);

                // 发起减库消息
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.setOrderId(orderId);
                List<OrderDetail> details = this.detailMapper.select(orderDetail);

                Map<String, List<String>> map = new HashMap<>();
                List<String> skuIds = null;
                if(!CollectionUtils.isEmpty(details)){
                    skuIds = details.stream()
                            .map(o -> o.getSkuId().toString() + "=" + o.getNum().toString()).collect(Collectors.toList());
                }
                map.put("orderId", skuIds);
                // 通过MQ发送减库消息
                this.amqpTemplate.convertAndSend(EXCHANGE, "order.pay.stock", map);
                log.info("订单被支付，发起减库通知! -- " + JSON.toJSONString(map));
                return payState;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return PayState.NOT_PAY;
    }
}
